/*
 * MQCommunicationService.h
 *
 *  Created on: Jul 17, 2013
 *      Author: m
 */

#ifndef MQCOMMUNICATIONSERVICE_H_
#define MQCOMMUNICATIONSERVICE_H_

#include "CommunicationService.h"
#include "MessageQueue.h"
#include <cstring>

#define MQCS_ADDRESS_MAXLENGTH 26
#define MQCS_DEFAULT_MTYPE 1

namespace communication
{

static const std::string mqcsRequestChannelBasename = "/tmp/mqcsrq-";
static const std::string mqcsReplyChannelBasename = "/tmp/mqcsrp-";

template <class T> struct MQMessageEnvelope
{
    char m_source[MQCS_ADDRESS_MAXLENGTH];
    char m_destination[MQCS_ADDRESS_MAXLENGTH];
    T m_message;

    MQMessageEnvelope()
    {
    }

    MQMessageEnvelope( std::string source, std::string destination, const T &message) :
        m_message( message )
    {
        if( source.size() >= MQCS_ADDRESS_MAXLENGTH || destination.size() >= MQCS_ADDRESS_MAXLENGTH )
        {
            throw Exception( "MQMessageEnvelope: Address too long." );
        }
        else
        {
            strncpy( m_source, source.c_str(), MQCS_ADDRESS_MAXLENGTH );
            strncpy( m_destination, source.c_str(), MQCS_ADDRESS_MAXLENGTH );
        }
    }

    MQMessageEnvelope( MQMessageEnvelope<T> const &other )
    {
        *this = other;
    }

    MQMessageEnvelope<T>& operator=( MQMessageEnvelope<T> const &rhs )
    {
        strncpy( this->m_source,rhs.m_source, MQCS_ADDRESS_MAXLENGTH );
        strncpy( this->m_destination, rhs.m_destination, MQCS_ADDRESS_MAXLENGTH );
        this->m_message =  rhs.m_message;

        return *this;
     }

};

template <class RequestType, class ReplyType> class MQCommunicationService :
        public CommunicationService<RequestType, ReplyType>
{
protected:
    std::string m_sourceName;
    std::string m_serviceName;
    MessageQueue< MQMessageEnvelope<RequestType> > m_requestChannel;
    MessageQueue< MQMessageEnvelope<ReplyType> > m_replyChannel;

public:
    MQCommunicationService( std::string sourceName, std::string serviceName = "" ) :
        m_sourceName( sourceName ),
        m_serviceName( serviceName ),
        m_requestChannel( mqcsRequestChannelBasename + m_serviceName + m_sourceName ),
        m_replyChannel( mqcsReplyChannelBasename + m_serviceName + m_sourceName )
    {

    }

    virtual ~MQCommunicationService()
    {

    }

    void send( std::string destination, RequestType &request )
    {
        MQMessageEnvelope<RequestType> messageEnvelope( m_sourceName, destination, request );

        m_requestChannel.put( MQCS_DEFAULT_MTYPE, messageEnvelope );
    }

    ReplyType recieve()
    {
        MQMessageEnvelope<ReplyType> messageEnvelope = m_replyChannel.get( MQCS_DEFAULT_MTYPE );

        return messageEnvelope.m_message;
    }
};

} /* namespace communication */
#endif /* MQCOMMUNICATIONSERVICE_H_ */
